import urllib2
import xml.dom.minidom
import re
import random
import xml.dom.minidom
import time
import binascii

GEOCODE_REQUEST_TEMPLATE = "http://maps.googleapis.com/maps/api/geocode/xml?sensor=false&address=%s"
status_re_pattern = re.compile(u'<status>(.+)</status>')
coordinate_re_pattern = re.compile(r"<location>\s+<lat>(-?\d+.-?\d+)</lat>\s+<lng>(-?\d+.-?\d+)</lng>\s+</location>")
address_re_pattern=re.compile(r"<short_name>(.+)</short_name>\s+<type>route</type>")
address_re_pattern2=re.compile(r"<short_name>(.+)</short_name>\s+<type>postal_code</type>")

question_re_pattern=re.compile(u"([^\?]+\?)\s(.*)")

def getCoordinatesIfMissing(trail_locality,node) :
    (lat,lon,method,node_name)=(None,None,None,None)
    try :
        node_name = node["name"]
    except :
        node_name = "<unnamed>"
    try :
        (lat,lon,method) = (node["latitude"],node["longitude"],"explicit")
    except :
        global_address = "%s, %s"%(node["name"], trail_locality)
        url = GEOCODE_REQUEST_TEMPLATE%global_address.replace(" ","+")
        (
            coord_match,type_match,address_match,
            tries_left,stop_trying
        )=(None,None,None,3,False)
        while(stop_trying != True) :
            url_response = urllib2.urlopen(url)
            response_text = unicode(url_response.read().decode('utf-8'))
            status_match = status_re_pattern.search(response_text)
            if(status_match is None) :
                # Nothing in the response is likely to be useable
                pass
            elif(status_match.group(1)=="OVER_QUERY_LIMIT") :
                # Google Maps API has spotted us doing too many queries,
                # too quickly
                pass
            elif(status_match.group(1)=="OK") :    
                coord_match=coordinate_re_pattern.search(response_text)
                address_match=address_re_pattern.search(response_text)
                if(address_match is None) :
                    address_match=address_re_pattern2.search(response_text)
                stop_trying=True
            else :
                print "Unexpected status: %s" % status_match.group(1)
            tries_left -= 1
            if(tries_left==0) :
                stop_trying = True
            elif(stop_trying!=True) :
                time.sleep(2.0)
        if(coord_match is None) :
            (lat,lon,method) = (0.0,0.0,"geocode failed")
        else :
            (lat,lon,method) = (
                coord_match.group(1), 
                coord_match.group(2),
                "geocode succeeded"
        )
    trace_msg = "( %s, %s ) = %s [%s]"% (lat,lon,node_name,method)
    return (lat,lon,trace_msg)

"""
    def openZone(self,zone_address,radius_metres,offset_metres=None,offset_bearing=None,question=None,answer=None) :
        self.addPoint(zone_address)
    def createElement(self,tag) :
        return self.doc.createElement(tag)
    def createTextNode(self,content) :
        return self.doc.createTextNode(content)
    def addAttribute(self,node,dict,tag) :
        try : node.attributes[tag] = str(dict[tag])
        except : pass
    def addTextElement(self,node,dict,tag) :
        tNode = self.doc.createElement(tag)
        tText = self.doc.createTextNode(dict[tag])
        tNode.appendChild(tText)
        node.appendChild(tNode)
    def addPoint(self,point_name,point_address=None,point_type=None,message=None) :
        if(self.currentPoint is not None) :
            raise Exception("Adding a point %s when %s is current"%(point_name,currentPoint["name"]))
        if(point_address is None) :
            (coords,address) = self.addressToCoordinates(point_name)
        else :
            (coords,dummy_address) = self.addressToCoordinates(point_address)
            address=point_address
        if(point_type is None) :
            point_type = 'unspecified'
        self.currentPoint = {}
        self.currentPoint["name"] = point_name
        self.currentPoint["address"] = address
        self.currentPoint["latitude"] = coords[0]
        self.currentPoint["longitude"] = coords[1]
        self.currentPoint["type"] = point_type
        self.currentPoint["radius_metres"] = "50"
        if(message) :
            question_match = question_re_pattern.search(message)
            if(question_match) :
                self.currentPoint["question"] = question_match.group(1)
                self.currentPoint["answer"] = question_match.group(2)
            else :
                self.currentPoint["message"] = message
        if(self.currentZone is not None) :
            self.currentZone["points"] += [ self.currentPoint ];
        else :
            self.points += [ self.currentPoint ]
        print self.currentPoint
        self.currentPoint = None
        return coords
    def addZone(self,radius_metres,points) :
        self.currentZone = {}
        self.currentZone["radius_metres"] = str(radius_metres)
        self.currentZone["points"] = []
        self.currentZone["latitude"] = 0.0
        self.currentZone["longitude"] = 0.0
        for p in points :
            coords = self.addPoint(p[0],p[1],p[2],p[3])
            self.currentZone["latitude"] += float(coords[0])
            self.currentZone["longitude"] += float(coords[1])
        self.currentZone["latitude"] /= len(points)
        self.currentZone["longitude"] /= len(points)
        self.zones += [self.currentZone]
        self.currentZone = None
    def addPointToTqz(self,attachmentNode,p) :
        pointNode = self.createElement("zone")
        self.addAttribute(pointNode,p,"name")
        self.addAttribute(pointNode,p,"address")
        self.addAttribute(pointNode,p,"type")
        self.addAttribute(pointNode,p,"question")
        self.addAttribute(pointNode,p,"answer")
        self.addAttribute(pointNode,p,"message")
        coordNode = self.createElement("coordinates")
        self.addAttribute(coordNode,p,"latitude")
        self.addAttribute(coordNode,p,"longitude")
        self.addAttribute(coordNode,p,"radius_metres")
        pointNode.appendChild(coordNode)
        attachmentNode.appendChild(pointNode)
    def addZoneToTqz(self,attachmentNode,z) :
        zoneNode = self.createElement("zone")
        coordNode = self.createElement("coordinates")
        self.addAttribute(coordNode,z,"latitude")
        self.addAttribute(coordNode,z,"longitude")
        self.addAttribute(coordNode,z,"radius_metres")
        zoneNode.appendChild(coordNode)
        for p in z["points"] :
            self.addPointToTqz(zoneNode,p)
        attachmentNode.appendChild(zoneNode)
    def addEncryptedNodeToTqz(self,attachmentNode,encryptedNodeName,plaintext) :
        pt = plaintext.encode('utf-8')
        # print pt
        ptlen = len(pt)
        ptcrc = '%08x' % (binascii.crc32(pt) & 0xffffffff)
        ct = ''
        while(len(pt)>0) :
            pt_block = pt[0:127]
            pt = pt[128:]
            ct += str(encrypting_key.encrypt(pt_block,""))
        ctlen = len(ct)
        ctcrc = '%08x' % (binascii.crc32(ct) & 0xffffffff)
        ct_b64 = ct.encode("base64")
        encryptedNode = self.createElement(encryptedNodeName)
        b64_cryptext_child = self.createTextNode("\n%s"%ct_b64)
        encryptedNode.appendChild(b64_cryptext_child)
        encryptedNode.attributes["ptlen"] = str(ptlen)
        encryptedNode.attributes["ptcrc"] = str(ptcrc)
        attachmentNode.appendChild(encryptedNode)            
        encryptedNode.attributes["ctlen"] = str(ctlen)
        encryptedNode.attributes["ctcrc"] = str(ctcrc)
    def toTqz(self,filename) :
        topNode = self.createElement("tw1")
        clearNode = self.createElement("tw1_plaintext")
        clearNode.attributes["version"]="1"
        clearNode.attributes["locality"]="%s"%(self.locality)
        for z in self.zones :
            self.addZoneToTqz(clearNode,z)
        for p in self.points :
            self.addPointToTqz(clearNode,p)
        topNode.appendChild(clearNode)
        xml_text = topNode.toprettyxml("","\n",'utf-8')
        self.addEncryptedNodeToTqz(topNode,"tw1_encrypted",xml_text)
        f = open(filename,"w")
        f.write('<?xml version="1.0" encoding="utf-8"?>\n')
        f.write(topNode.toprettyxml("","\n",'utf-8'))
        f.close()
    def toPy(self,filename) :
        f = open(filename,"w")
        f.write("trail = {\n")
        f.write("    'version':'1', 'locality':'%s',\n"%(self.locality))
        f.write("    'zones' : (\n")
        for z in self.zones :
            f.write("        (%s),\n"%str(z))
        f.write("    ),\n")
        f.write("    'points' : (\n")
        for p in self.points :
            f.write('        (%s),\n'%str(p))
        f.write("    ),\n")
        f.write("}")
    def addWaypointToGpx(self,f,pos) :
        f.write('    <wpt lat="%f" lon="%f"><name>(%f,%f)</name></wpt>\n'%(pos[0],pos[1],pos[0],pos[1]))        
    def toGpx(self,filename,intermediate_point_count=10) :
        f = open(filename,"w")
        f.write('<?xml version="1.0"?>\n<gpx version="1.1" creator="Xcode">\n')
        points = self.points[:1]
        for z in self.zones :
            points += z["points"]
        points += self.points[1:]
        # points += points[0]
        if(len(points)>0) :
            pos = (float(points[0]["latitude"]),float(points[0]["longitude"]))
            self.addWaypointToGpx(f,pos)
            for p in points[1:] :
                next_pos = (float(p["latitude"]),float(p["longitude"]))
            	intermediate_point_count = 10 + int(1000.0*(abs(next_pos[0]-pos[0]) + abs(next_pos[0]-pos[0])))
            	print "ipc=%d" % intermediate_point_count
                delta_lat = (next_pos[0] - pos[0]) / intermediate_point_count
                delta_long = (next_pos[1] - pos[1]) / intermediate_point_count
                for i in range(0,intermediate_point_count) :
                    pos = (pos[0]+delta_lat,pos[1]+delta_long)
                    self.addWaypointToGpx(f,pos)
                pos = next_pos
                self.addWaypointToGpx(f,pos)
            self.addWaypointToGpx(f,pos)
        f.write('</gpx>\n')
    def gen_files(self,filename) :
        self.toTqz("./%s.tqz"%(filename))
        self.toTqz("./%s_debug.tqz"%(filename))
        self.toPy("./gen_%s.py"%(filename))
        self.toGpx("./%s.gpx"%(filename))
    
"""